package network

import (
	"github.com/vishvananda/netlink"
	"net"
)

// 定义网桥两种网络模型
type BridgeMethod int8

const (
	BridgeMethodNat BridgeMethod = iota
	BridgeMethodBridge
)

type BridgeNetworkOptions struct {
	Addr     *net.IPNet
	Method   BridgeMethod
	BridgeTo []string // 需要在创建后桥接的接口
}

func (opt BridgeNetworkOptions) IP() net.IP {
	return opt.Addr.IP
}

func (opt BridgeNetworkOptions) Mask() net.IPMask {
	return opt.Addr.Mask
}

type bridgeNetwork struct {
	name     string
	addr     *net.IPNet
	method   BridgeMethod
	link     netlink.Link
	bridgeTo []string
}

func createBridgeNetwork(name string, opt *BridgeNetworkOptions) *bridgeNetwork {
	br := &bridgeNetwork{
		name:     name,
		addr:     opt.Addr,
		method:   opt.Method,
		bridgeTo: opt.BridgeTo,
	}
	return br
}

// 配置网桥
func (br *bridgeNetwork) Setup() error {
	// 创建网络接口
	link := netlink.NewLinkAttrs()
	link.Name = br.name
	bridge := netlink.Bridge{
		LinkAttrs: link,
	}
	if err := netlink.LinkAdd(&bridge); err != nil {
		return err
	}
	br.link = &bridge
	if err := netlink.LinkSetUp(br.link); err != nil {
		return err
	}
	// 设置网络
	if br.addr != nil {
		if err := manager.Register(br.name, *br.addr); err != nil {
			return err
		}
		if err := netlink.AddrAdd(&bridge, &netlink.Addr{IPNet: br.addr}); err != nil {
			_ = manager.Unregister(br.name)
			return err
		}
	}
	// 设置网桥工作模式
	switch br.method {
	case BridgeMethodBridge:
		// todo: 实现桥接
		return NotImplement
	default:
		// 默认使用nat模式
		return setupNat(br.name, br.addr)
	}
}

func (br *bridgeNetwork) Release(ip net.IP) error {
	return manager.Release(br.name, ip)
}

func (br *bridgeNetwork) Remove() error {
	err := netlink.LinkSetDown(br.link)
	if err != nil {
		return err
	}
	return netlink.LinkDel(br.link)
}

func (br *bridgeNetwork) Type() string {
	return "bridge"
}

func (br *bridgeNetwork) Name() string {
	return br.name
}

func (br *bridgeNetwork) Addr() *net.IPNet {
	return br.addr
}

func (br *bridgeNetwork) Allocate() (net.IP, net.IP, error) {
	return manager.Allocate(br.name)
}
